package pers.xiaojun.boot.module.system.service.permission;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ArrayUtil;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import pers.xiaojun.boot.common.enums.CommonStatusEnum;
import pers.xiaojun.boot.common.exception.BusinessException;
import pers.xiaojun.boot.common.util.CollectionUtils;
import pers.xiaojun.boot.module.system.constants.BusinessCodeConstants;
import pers.xiaojun.boot.module.system.controller.auth.vo.AuthPermissionInfoRespVO;
import pers.xiaojun.boot.module.system.controller.permission.vo.permission.AssignRoleMenuReqVO;
import pers.xiaojun.boot.module.system.controller.permission.vo.permission.AssignUserRoleReqVO;
import pers.xiaojun.boot.module.system.convert.AuthConvert;
import pers.xiaojun.boot.module.system.dao.entity.permission.MenuDO;
import pers.xiaojun.boot.module.system.dao.entity.permission.RoleDO;
import pers.xiaojun.boot.module.system.dao.entity.permission.RoleMenuDO;
import pers.xiaojun.boot.module.system.dao.entity.user.AdminUserDO;
import pers.xiaojun.boot.module.system.dao.mapper.permission.UserRoleMapper;
import pers.xiaojun.boot.module.system.service.tenant.TenantPackageService;
import pers.xiaojun.boot.module.system.service.user.UserService;
import pers.xiaojun.boot.security.util.SecurityUtils;

import java.util.List;
import java.util.Set;

/**
 * 权限实现类
 *
 * @author xiaojun
 * @since 2025-10-10
 */
@Service
@RequiredArgsConstructor
public class PermissionServiceImpl implements PermissionService {

    private final UserRoleService userRoleService;
    private final RoleMenuService roleMenuService;
    private final MenuService menuService;
    private final RoleService roleService;
    private final UserService userService;
    private final TenantPackageService tenantPackageService;

    @Override
    public boolean hasAnyPermissions(Long userId, String... permissions) {
        // 为空说明不需要权限
        if (ArrayUtil.isEmpty(permissions)) {
            return true;
        }
        // 获取当前用户角色Id列表
        List<Long> roleIds = userRoleService.listRoleIdsByUserId(userId);

        // 如果为超级管理员直接返回（拥有所有权限）
        if (roleService.hasAnySuperAdmin(roleIds)) {
            return true;
        }
        // 依次判断是否拥有权限
        for (String permission : permissions) {
            if (hasPermission(roleIds, permission)) {
                return true;
            }
        }
        // 默认没有权限
        return false;
    }

    @Override
    public boolean hasAnyRoles(Long userId, String... roles) {
        List<Long> roleIds = userRoleService.listRoleIdsByUserId(userId);
        List<String> roleCodes = roleService.listRolesByIds(roleIds).stream()
                .map(RoleDO::getCode)
                .toList();
        return CollUtil.containsAny(roleCodes, Lists.newArrayList(roles));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void assignUserRole(AssignUserRoleReqVO assignRoleVO) {
        // 校验用户是否存在
        userService.validateUserExists(assignRoleVO.getUserId());
        // 校验角色Id是否存在
        roleService.validateRolesExists(assignRoleVO.getRoleIds());

        // 当前拥有的角色Id
        Set<Long> oldRoleIds = Sets.newHashSet(userRoleService.listRoleIdsByUserId(assignRoleVO.getUserId()));

        // 当前拥有 - 添加角色 = 需要删除的角色
        Sets.SetView<Long> deleteIds = Sets.difference(oldRoleIds, assignRoleVO.getRoleIds());
        if (CollUtil.isNotEmpty(deleteIds)) {
            userRoleService.removeUserRoleByUserIdAndRoleIds(
                    assignRoleVO.getUserId(),
                    deleteIds
            );
        }

        // 添加角色 - 当前拥有 = 需要添加的角色
        Sets.SetView<Long> saveIds = Sets.difference(assignRoleVO.getRoleIds(), oldRoleIds);
        if (CollUtil.isNotEmpty(saveIds)) {
            userRoleService.saveUserRoles(
                    assignRoleVO.getUserId(),
                    saveIds
            );
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void assignRoleMenu(AssignRoleMenuReqVO assignMenuVO) {
        // 校验角色是否存在
        roleService.validateRoleExists(assignMenuVO.getRoleId());
        // 校验菜单是否存在
        menuService.validateMenusExists(assignMenuVO.getMenuIds());

        // 获取现有菜单Id
        Set<Long> presentMenuIds = Sets.newHashSet(roleMenuService.listMenuIdsByRoleId(assignMenuVO.getRoleId()));

        // 删除需要移除的菜单Id
        Sets.SetView<Long> deleteIds = Sets.difference(presentMenuIds, assignMenuVO.getMenuIds());
        if (CollUtil.isNotEmpty(deleteIds)) {
            roleMenuService.removeByRoleIdAndMenuIds(
                    assignMenuVO.getRoleId(),
                    deleteIds
            );
        }

        // 添加新的菜单Id
        Sets.SetView<Long> saveIds = Sets.difference(assignMenuVO.getMenuIds(), presentMenuIds);
        if (CollUtil.isNotEmpty(saveIds)) {
            roleMenuService.saveRoleMenus(
                    assignMenuVO.getRoleId(),
                    saveIds
            );
        }
    }

    @Override
    public AuthPermissionInfoRespVO getUserPermission() {
        // 1.获取用户信息
        AdminUserDO user = userService.getById(SecurityUtils.getUserId());
        if (user == null) {
            throw new BusinessException(BusinessCodeConstants.USER_NOT_EXISTS);
        }
        // 2.获取用户角色信息
        List<Long> roleIds = userRoleService.listRoleIdsByUserId(user.getId());
        List<RoleDO> roles = roleService.listRolesByIds(roleIds);
        // 移除禁用角色
        roles.removeIf(rule -> CommonStatusEnum.isDisable(rule.getStatus()));
        // 3.获取用户菜单
        boolean hasSuperAdmin = roleService.hasAnySuperAdmin(roleIds);
        List<MenuDO> menus;
        if (hasSuperAdmin) {
            // 如果是超级管理员，则获取所有
            menus = menuService.list();
        } else {
            List<Long> menuIds = roleMenuService.listMenuIdsByRoleIds(roleIds);
            menus = menuService.listByIds(menuIds);
        }

        return AuthConvert.INSTANCE.toAuthPermissionInfoRespVO(user, roles, menus);
    }

    @Override
    public List<Long> listMenuIdsByRoleId(Long roleId) {
        if (roleService.hasSuperAdmin(roleId)) {
            return CollectionUtils.convertList(menuService.list(), MenuDO::getId);
        }
        return roleMenuService.listMenuIdsByRoleId(roleId);
    }

    @Override
    public List<Long> listRoleIdsByUserId(Long userId) {
        userService.validateUserExists(userId);

        return userRoleService.listRoleIdsByUserId(userId);
    }

    @Override
    public List<RoleDO> listRolesByUserId(Long userId) {
        List<Long> roleIds = userRoleService.listRoleIdsByUserId(userId);
        if (CollUtil.isNotEmpty(roleIds)) {
            return roleService.listRolesByIds(roleIds);
        }
        return List.of();
    }

    /**
     * 判断角色是否拥有单个权限
     *
     * @param roleIds    角色Id列表
     * @param permission 权限标识
     * @return 是否拥有
     */
    private boolean hasPermission(List<Long> roleIds, String permission) {
        // 获取权限对应的菜单Id
        List<Long> menuIds = menuService.listMenuIdsByPermission(permission);
        // 为空表示没有权限
        if (menuIds.isEmpty()) {
            return false;
        }
        // 判断角色中是否拥有对应的菜单Id
        for (Long roleId : roleIds) {
            // 获取角色对应的菜单Id
            List<Long> roleMenuIds = roleMenuService.listMenuIdsByRoleId(roleId);
            // 权限菜单Id列表 与 角色拥有的菜单Id 是否有交集，有则表示有权限
            if (CollUtil.containsAny(menuIds, roleMenuIds)) {
                return true;
            }
        }
        // 默认没有权限
        return false;
    }


}
